﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Threading;

namespace WpfStarterKit.Framework.Navigation
{
    /// <summary>
    /// This class wraps the logic for running long running operations. These are view model methods decorated with the 
    /// LongRunningOperation attribute
    /// </summary>
    public class LongRunningOperationExecutionManager
    {
        /// <summary>
        /// The dispatcher used by this manager. This is picked up from the CurrentView automatically, so there's no 
        /// need to populate this property
        /// </summary>
        public Dispatcher Dispatcher { get; set; }

        /// <summary>
        /// The LongRunningOperationAttribute that was used to decorate the method
        /// </summary>
        public LongRunningOperationAttribute Wait { get; set; }

        /// <summary>
        /// The operation to be executed
        /// </summary>
        public Delegate Operation { get; set; }

        /// <summary>
        /// Any paramters required by the Operation delegate
        /// </summary>
        public object[] OperationParameters { get; set; }

        /// <summary>
        /// Raised when the method has finished executing
        /// </summary>
        public event EventHandler Executed;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="wait">The LongRunningOperationAttribute that was used to decorate the method</param>
        /// <param name="operation">The operation to be executed</param>
        /// <param name="operationParameters">Any paramters required by the Operation delegate</param>
        public LongRunningOperationExecutionManager(LongRunningOperationAttribute wait, Delegate operation, params object[] operationParameters)
        {
            Wait = wait;
            Operation = operation;
            OperationParameters = operationParameters;

            if (ApplicationManager.Instance.Navigation.CurrentView != null)
            {
                Dispatcher = ApplicationManager.Instance.Navigation.CurrentView.Dispatcher;
            }
        }

        /// <summary>
        /// Execute the long running operation
        /// </summary>
        public void Execute()
        {
            var showWaitOperation =
                Dispatcher.BeginInvoke(
                    new Action<LongRunningOperationAttribute>(ApplicationManager.Instance.LongRunningOperations.LongRunningOperationStarted),
                    DispatcherPriority.Render, new object[] {Wait});
            showWaitOperation.Completed += showWaitOperation_Completed;
        }

        void showWaitOperation_Completed(object sender, EventArgs e)
        {
            var op = Dispatcher.BeginInvoke(Operation, DispatcherPriority.Background, OperationParameters);
            op.Completed += op_Completed;
        }

        void op_Completed(object sender, EventArgs e)
        {
            ApplicationManager.Instance.LongRunningOperations.LongRunningOperationCompleted(Wait);
            if (Executed != null)
            {
                Executed(this, new EventArgs());
            }
        }
    }
}
